<!DOCTYPE html>
<html lang="zh-CN">

<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Melody Chat API 文档</title>
    <style>
        :root {
            --primary-color: #4a90e2;
            --secondary-color: #f5f5f5;
            --text-color: #333;
            --border-color: #ddd;
        }

        * {
            margin: 0;
            padding: 0;
            box-sizing: border-box;
        }

        body {
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
            line-height: 1.6;
            color: var(--text-color);
            background-color: #fff;
        }

        .container {
            max-width: 1200px;
            margin: 0 auto;
            padding: 20px;
            display: flex;
        }

        .sidebar {
            width: 250px;
            position: fixed;
            height: 100vh;
            overflow-y: auto;
            background-color: var(--secondary-color);
            padding: 20px;
            border-right: 1px solid var(--border-color);
        }

        .main-content {
            margin-left: 270px;
            flex: 1;
            padding: 20px;
        }

        .logo {
            text-align: center;
            margin-bottom: 30px;
        }

        .logo h1 {
            color: var(--primary-color);
            font-size: 24px;
        }

        .nav-list {
            list-style: none;
        }

        .nav-item {
            margin-bottom: 10px;
        }

        .nav-link {
            color: var(--text-color);
            text-decoration: none;
            display: block;
            padding: 8px 12px;
            border-radius: 4px;
            transition: background-color 0.3s;
        }

        .nav-link:hover {
            background-color: rgba(74, 144, 226, 0.1);
        }

        .nav-link.active {
            background-color: var(--primary-color);
            color: white;
        }

        section {
            margin-bottom: 40px;
            padding: 20px;
            background-color: white;
            border-radius: 8px;
            box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
        }

        h2 {
            color: var(--primary-color);
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 2px solid var(--primary-color);
        }

        h3 {
            margin: 20px 0 10px;
            color: var(--text-color);
        }

        .api-endpoint {
            background-color: var(--secondary-color);
            padding: 15px;
            border-radius: 4px;
            margin: 10px 0;
        }

        .method {
            display: inline-block;
            padding: 4px 8px;
            border-radius: 4px;
            color: white;
            font-weight: bold;
            margin-right: 10px;
        }

        .method.get {
            background-color: #61affe;
        }

        .method.post {
            background-color: #49cc90;
        }

        .method.put {
            background-color: #fca130;
        }

        .method.delete {
            background-color: #f93e3e;
        }

        pre {
            background-color: #f8f8f8;
            padding: 15px;
            border-radius: 4px;
            overflow-x: auto;
            margin: 10px 0;
        }

        code {
            font-family: Consolas, Monaco, 'Andale Mono', monospace;
        }

        table {
            width: 100%;
            border-collapse: collapse;
            margin: 15px 0;
        }

        th,
        td {
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid var(--border-color);
        }

        th {
            background-color: var(--secondary-color);
            font-weight: bold;
        }

        @media (max-width: 768px) {
            .container {
                flex-direction: column;
            }

            .sidebar {
                width: 100%;
                position: relative;
                height: auto;
                margin-bottom: 20px;
            }

            .main-content {
                margin-left: 0;
            }
        }
    </style>
</head>

<body>
    <div class="container">
        <nav class="sidebar">
            <div class="logo">
                <h1>Melody Chat API</h1>
            </div>
            <ul class="nav-list">
                <li class="nav-item"><a href="#overview" class="nav-link">项目概述</a></li>
                <li class="nav-item"><a href="#user-api" class="nav-link">用户管理 API</a></li>
                <li class="nav-item"><a href="#chatroom-api" class="nav-link">聊天室 API</a></li>
                <li class="nav-item"><a href="#websocket-api" class="nav-link">WebSocket API</a></li>
            </ul>
        </nav>

        <main class="main-content">
            <section id="overview">
                <h2>项目概述</h2>
                <p>Melody Chat 是一个集成了音乐播放功能的实时聊天应用，支持私聊、群聊和游客模式。</p>

                <h3>系统要求</h3>
                <ul>
                    <li>操作系统：Windows 10 或更高版本</li>
                    <li>浏览器：支持 WebSocket 的现代浏览器（Chrome、Firefox、Edge 等）</li>
                    <li>网络环境：稳定的互联网连接</li>
                    <li>访问地址：http://8.138.152.233:5051</li>
                </ul>
            </section>

            <section id="user-api">
                <h2>用户管理 API</h2>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/users/register</code>
                    <p>用户注册</p>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "email": "user@example.com",
    "name": "用户名",
    "password": "密码",
    "verificationCode": "验证码"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "注册成功",
    "data": {
        "id": 1,
        "email": "user@example.com",
        "name": "用户名"
    }
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/users/send-code</code>
                    <p>发送注册验证码</p>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "email": "user@example.com"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "验证码已发送，请查收"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/users/login</code>
                    <p>密码登录</p>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "email": "user@example.com",
    "password": "密码"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "登录成功",
    "data": {
        "token": "JWT_TOKEN",
        "user": {
            "id": 1,
            "name": "用户名",
            "email": "user@example.com",
            "avatar": "头像URL"
        }
    }
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/users/login-code</code>
                    <p>验证码登录</p>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "email": "user@example.com",
    "verificationCode": "验证码"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "登录成功",
    "data": {
        "token": "JWT_TOKEN",
        "user": {
            "id": 1,
            "name": "用户名",
            "email": "user@example.com",
            "avatar": "头像URL"
        }
    }
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/users/login-send-code</code>
                    <p>发送登录验证码</p>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "email": "user@example.com"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "验证码已发送，请查收"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/users/reset-password</code>
                    <p>重置密码</p>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "email": "user@example.com",
    "verificationCode": "验证码",
    "newPassword": "新密码"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "密码重置成功"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/users/reset-password-code</code>
                    <p>发送重置密码验证码</p>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "email": "user@example.com"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "验证码已发送，请查收"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/visitors/login</code>
                    <p>游客登录</p>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "name": "游客昵称"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "登录成功",
    "data": {
        "token": "JWT_TOKEN",
        "user": {
            "name": "游客昵称",
            "isVisitor": true
        }
    }
}</code></pre>
                </div>

                <h3>需要认证的接口</h3>

                <div class="api-endpoint">
                    <span class="method get">GET</span>
                    <code>/api/users/me</code>
                    <p>获取当前用户信息</p>
                    <h4>请求头</h4>
                    <pre><code>Authorization: Bearer JWT_TOKEN</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": {
        "id": 1,
        "name": "用户名",
        "email": "user@example.com",
        "avatar": "头像URL",
        "gender": "male",
        "birthdate": "1990-01-01"
    }
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method get">GET</span>
                    <code>/api/users/list</code>
                    <p>获取用户列表</p>
                    <h4>请求头</h4>
                    <pre><code>Authorization: Bearer JWT_TOKEN</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": [
        {
            "id": 1,
            "name": "用户名",
            "email": "user@example.com",
            "avatar": "头像URL",
            "gender": "male",
            "birthdate": "1990-01-01"
        }
    ]
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method get">GET</span>
                    <code>/api/users/search</code>
                    <p>搜索用户</p>
                    <h4>请求头</h4>
                    <pre><code>Authorization: Bearer JWT_TOKEN</code></pre>
                    <h4>请求参数</h4>
                    <pre><code>?keyword=搜索关键词</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": [
        {
            "id": 1,
            "name": "用户名",
            "email": "user@example.com",
            "avatar": "头像URL"
        }
    ]
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method put">PUT</span>
                    <code>/api/users/update</code>
                    <p>更新用户信息</p>
                    <h4>请求头</h4>
                    <pre><code>Authorization: Bearer JWT_TOKEN</code></pre>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "name": "新用户名",
    "gender": "female",
    "avatar": "新头像URL"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "用户信息更新成功"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method get">GET</span>
                    <code>/api/users/relationships</code>
                    <p>获取用户关系</p>
                    <h4>请求头</h4>
                    <pre><code>Authorization: Bearer JWT_TOKEN</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": {
        "friends": [
            {
                "id": 2,
                "name": "好友名称",
                "email": "friend@example.com",
                "avatar": "头像URL"
            }
        ],
        "pending": [
            {
                "id": 3,
                "name": "待处理用户",
                "email": "pending@example.com",
                "avatar": "头像URL"
            }
        ]
    }
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method get">GET</span>
                    <code>/api/users/friend-requests</code>
                    <p>获取好友申请</p>
                    <h4>请求头</h4>
                    <pre><code>Authorization: Bearer JWT_TOKEN</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": [
        {
            "id": 1,
            "from": {
                "id": 2,
                "name": "申请人",
                "email": "applicant@example.com",
                "avatar": "头像URL"
            },
            "status": "pending",
            "createdAt": "2024-01-01T12:00:00.000Z"
        }
    ]
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method put">PUT</span>
                    <code>/api/users/update-relationship</code>
                    <p>更新用户关系</p>
                    <h4>请求头</h4>
                    <pre><code>Authorization: Bearer JWT_TOKEN</code></pre>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "userId": 2,
    "action": "accept" // accept, reject, block
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "关系更新成功"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/users/create-relationship</code>
                    <p>创建用户关系</p>
                    <h4>请求头</h4>
                    <pre><code>Authorization: Bearer JWT_TOKEN</code></pre>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "userId": 2,
    "type": "friend" // friend, block
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "好友申请已发送"
}</code></pre>
                </div>
            </section>

            <section id="chatroom-api">
                <h2>聊天室 API</h2>

                <div class="api-endpoint">
                    <span class="method get">GET</span>
                    <code>/api/chatroom-list</code>
                    <p>获取所有聊天室列表</p>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": [
        {
            "roomID": 1,
            "img": "聊天室图片URL",
            "title": "聊天室标题",
            "intro": "聊天室简介",
            "maxUsersLength": 100,
            "isPlaying": true,
            "currentSong": {
                "id": "歌曲ID",
                "name": "歌曲名称",
                "time": "歌曲时长",
                "author": "歌手",
                "picUrl": "歌曲封面URL"
            }
        }
    ]
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method get">GET</span>
                    <code>/api/chatroom/:roomId</code>
                    <p>获取单个聊天室信息</p>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": {
        "roomID": 1,
        "img": "聊天室图片URL",
        "title": "聊天室标题",
        "intro": "聊天室简介",
        "maxUsersLength": 100,
        "isPlaying": true,
        "currentSong": {
            "id": "歌曲ID",
            "name": "歌曲名称",
            "time": "歌曲时长",
            "author": "歌手",
            "picUrl": "歌曲封面URL"
        },
        "users": [
            {
                "id": 1,
                "name": "用户名",
                "avatar": "头像URL"
            }
        ]
    }
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method get">GET</span>
                    <code>/api/chatroom/:roomId/songs</code>
                    <p>获取聊天室歌曲列表</p>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": [
        {
            "id": "歌曲ID",
            "name": "歌曲名称",
            "time": "歌曲时长",
            "author": "歌手",
            "picUrl": "歌曲封面URL"
        }
    ]
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/chatroom/:roomId/songs</code>
                    <p>添加歌曲到聊天室</p>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "id": "歌曲ID",
    "name": "歌曲名称",
    "time": 180,
    "author": "歌手",
    "picUrl": "歌曲封面URL"
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "歌曲添加成功",
    "data": {
        "song": {
            "id": "歌曲ID",
            "name": "歌曲名称",
            "time": 180,
            "author": "歌手",
            "picUrl": "歌曲封面URL"
        }
    }
}</code></pre>
                </div>
            </section>

            <section id="message-api">
                <h2>消息 API</h2>

                <div class="api-endpoint">
                    <span class="method post">POST</span>
                    <code>/api/messages/delete</code>
                    <p>删除聊天记录</p>
                    <h4>请求头</h4>
                    <pre><code>Authorization: Bearer JWT_TOKEN</code></pre>
                    <h4>请求数据格式</h4>
                    <pre><code>{
    "messageIds": [1, 2, 3],
    "chatType": "private" // private, group
}</code></pre>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "message": "消息删除成功"
}</code></pre>
                </div>
            </section>

            <section id="visitor-api">
                <h2>访客 API</h2>

                <div class="api-endpoint">
                    <span class="method get">GET</span>
                    <code>/api/visitor-stats</code>
                    <p>获取访客统计</p>
                    <h4>响应数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": {
        "today_visitors": 100,
        "total_visitors": 1000
    }
}</code></pre>
                </div>
            </section>

            <section id="websocket-api">
                <h2>WebSocket API</h2>

                <h3>连接说明</h3>
                <p>WebSocket 服务地址: <code>ws://localhost:5050</code></p>
                <p>需要在连接时提供认证 token</p>
                <pre><code>const socket = io('ws://localhost:5050', {
    auth: {
        token: 'JWT_TOKEN'
    }
});</code></pre>

                <h3>事件列表</h3>

                <div class="api-endpoint">
                    <h4>发送私信</h4>
                    <p>事件名: <code>private_message</code></p>
                    <h4>发送数据格式</h4>
                    <pre><code>{
    "recipientEmail": "receiver@example.com",
    "message": "你好！这是一条私信",
    "type": 0
}</code></pre>
                    <h4>接收数据格式</h4>
                    <pre><code>{
    "id": 1,
    "from": {
        "id": 1,
        "email": "sender@example.com",
        "name": "发送者昵称",
        "avatar": "发送者头像URL"
    },
    "message": "消息内容",
    "type": 0,
    "timestamp": "2024-01-01T12:00:00.000Z",
    "is_read": false
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <h4>发送私信提示</h4>
                    <p>事件名: <code>private_message_hint</code></p>
                    <h4>发送数据格式</h4>
                    <pre><code>{
    "recipientEmail": "receiver@example.com",
    "message": "提示消息",
    "type": 0
}</code></pre>
                    <h4>接收数据格式</h4>
                    <pre><code>{
    "from": {
        "id": 1,
        "email": "sender@example.com",
        "name": "发送者昵称",
        "avatar": "发送者头像URL"
    },
    "message": "提示消息",
    "type": 0,
    "timestamp": "2024-01-01T12:00:00.000Z"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <h4>获取聊天记录</h4>
                    <p>事件名: <code>get_chat_history</code></p>
                    <h4>发送数据格式</h4>
                    <pre><code>{
    "otherUserEmail": "other@example.com"
}</code></pre>
                    <h4>接收数据格式</h4>
                    <pre><code>{
    "messages": [
        {
            "id": 1,
            "sender_id": 1,
            "recipient_id": 2,
            "message": "消息内容",
            "type": 0,
            "timestamp": "2024-01-01T12:00:00.000Z",
            "is_read": 0,
            "sender_name": "发送者昵称",
            "sender_avatar": "发送者头像URL",
            "recipient_name": "接收者昵称",
            "recipient_avatar": "接收者头像URL"
        }
    ],
    "otherUser": {
        "id": 2,
        "email": "other@example.com",
        "name": "对方昵称",
        "avatar": "对方头像URL"
    }
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <h4>标记消息已读</h4>
                    <p>事件名: <code>mark_as_read</code></p>
                    <h4>发送数据格式</h4>
                    <pre><code>{
    "senderEmail": "sender@example.com"
}</code></pre>
                    <h4>接收数据格式</h4>
                    <pre><code>{
    "senderEmail": "sender@example.com"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <h4>群聊消息</h4>
                    <p>事件名: <code>group:message</code></p>
                    <h4>发送数据格式</h4>
                    <pre><code>{
    "groupId": "群聊ID",
    "content": "消息内容"
}</code></pre>
                    <h4>接收数据格式</h4>
                    <pre><code>{
    "id": "消息ID",
    "groupId": "群聊ID",
    "content": "消息内容",
    "sender": {
        "id": "发送者ID",
        "name": "发送者昵称",
        "avatar": "发送者头像URL",
        "isVisitor": true/false
    },
    "timestamp": "2024-01-01T12:00:00.000Z"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <h4>加入群聊</h4>
                    <p>事件名: <code>group:join</code></p>
                    <h4>发送数据格式</h4>
                    <pre><code>{
    "groupId": "群聊ID"
}</code></pre>
                    <h4>接收数据格式</h4>
                    <pre><code>{
    "groupId": "群聊ID",
    "messages": [
        {
            "id": "消息ID",
            "groupId": "群聊ID",
            "content": "消息内容",
            "sender": {
                "id": "发送者ID",
                "name": "发送者昵称",
                "avatar": "发送者头像URL",
                "isVisitor": true/false
            },
            "timestamp": "2024-01-01T12:00:00.000Z"
        }
    ]
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <h4>离开群聊</h4>
                    <p>事件名: <code>group:leave</code></p>
                    <h4>发送数据格式</h4>
                    <pre><code>{
    "groupId": "群聊ID"
}</code></pre>
                </div>

                <div class="api-endpoint">
                    <h4>获取Cookie</h4>
                    <p>事件名: <code>cookie:get</code></p>
                    <h4>接收数据格式</h4>
                    <pre><code>{
    "status": "success",
    "data": {
        "cookie": "cookie值"
    }
}</code></pre>
                </div>

                <h3>系统事件</h3>
                <ul>
                    <li>
                        <code>connection:success</code> - 连接成功
                        <pre><code>{
    "status": "success",
    "message": "连接成功",
    "socketId": "socket_id"
}</code></pre>
                    </li>
                    <li>
                        <code>error</code> - 错误消息
                        <pre><code>{
    "message": "错误信息"
}</code></pre>
                    </li>
                    <li>
                        <code>group:member_left</code> - 群成员离开
                        <pre><code>{
    "groupId": "群聊ID",
    "user": {
        "avatar": "头像URL",
        "name": "用户名",
        "email": "用户邮箱",
        "isVisitor": true/false
    }
}</code></pre>
                    </li>
                    <li>
                        <code>group:all_groups</code> - 所有群聊信息
                        <pre><code>{
    "groups": [
        {
            "groupId": "群聊ID",
            "name": "群聊名称",
            "members": [
                {
                    "id": "用户ID",
                    "name": "用户名",
                    "avatar": "头像URL",
                    "isVisitor": true/false
                }
            ]
        }
    ]
}</code></pre>
                    </li>
                    <li>
                        <code>group:online_users_not_in_groups</code> - 在线但未加入群聊的用户列表
                        <pre><code>{
    "users": [
        {
            "id": "用户ID",
            "name": "用户名",
            "avatar": "头像URL",
            "isVisitor": true/false
        }
    ]
}</code></pre>
                    </li>
                </ul>
            </section>
        </main>
    </div>

    <script>
        // 高亮当前导航项
        document.addEventListener('DOMContentLoaded', function () {
            const navLinks = document.querySelectorAll('.nav-link');
            const sections = document.querySelectorAll('section');

            function setActiveLink() {
                let currentSection = '';
                sections.forEach(section => {
                    const sectionTop = section.offsetTop;
                    const sectionHeight = section.clientHeight;
                    if (window.pageYOffset >= sectionTop - 60) {
                        currentSection = section.getAttribute('id');
                    }
                });

                navLinks.forEach(link => {
                    link.classList.remove('active');
                    if (link.getAttribute('href').slice(1) === currentSection) {
                        link.classList.add('active');
                    }
                });
            }

            window.addEventListener('scroll', setActiveLink);
            setActiveLink();
        });
    </script>
</body>

</html>